#include "StdAfx.h"
#include "RendElement.h"
#include "CRESky.h"
#include "Stars.h"
#include "I3DEngine.h"

#if defined(DIRECT3D9) || defined(DIRECT3D10)
#include "../../XRenderD3D9/DriverD3D.h"
#endif


void CRESky::mfPrepare(bool bCheckOverflow)
{
  if (bCheckOverflow)
    gRenDev->FX_CheckOverflow(0, 0, this);

  gRenDev->m_RP.m_pRE = this;
  gRenDev->m_RP.m_RendNumIndices = 0;
  gRenDev->m_RP.m_RendNumVerts = 0;
}

float CRESky::mfDistanceToCameraSquared(Matrix34& matInst)
{
  return 999999.0f;
}

CRESky::~CRESky()
{
}


//////////////////////////////////////////////////////////////////////////
// HDR Sky
//////////////////////////////////////////////////////////////////////////

void CREHDRSky::GenerateSkyDomeTextures(int32 width, int32 height)
{
	SAFE_RELEASE(m_pSkyDomeTextureMie);
	SAFE_RELEASE(m_pSkyDomeTextureRayleigh);

#if defined(DIRECT3D10) || defined(DIRECT3D9)
	int creationFlags = FT_STATE_CLAMP | FT_NOMIPS;
#	if defined(DIRECT3D9) && !defined(XENON)
	creationFlags |= FT_USAGE_DYNAMIC;
#	endif

	const bool fp16Filtering = gcpRendD3D->m_bDeviceSupportsFP16Filter;
	if (fp16Filtering)
		creationFlags |= FT_FILTER_LINEAR;

	m_pSkyDomeTextureMie = CTexture::Create2DTexture("$SkyDomeTextureMie", width, height, 1, creationFlags, 0, eTF_A16B16G16R16F, eTF_A16B16G16R16F);
	m_pSkyDomeTextureMie->Fill(ColorF(0, 0, 0, 0));
	m_pSkyDomeTextureMie->SetFilterMode(fp16Filtering ? FILTER_LINEAR : FILTER_POINT);
	m_pSkyDomeTextureMie->SetClampingMode(0, 1, 1);
	m_pSkyDomeTextureMie->UpdateTexStates();

	m_pSkyDomeTextureRayleigh = CTexture::Create2DTexture("$SkyDomeTextureRayleigh", width, height, 1, creationFlags, 0, eTF_A16B16G16R16F, eTF_A16B16G16R16F);
	m_pSkyDomeTextureRayleigh->Fill(ColorF(0, 0, 0, 0));
	m_pSkyDomeTextureRayleigh->SetFilterMode(fp16Filtering ? FILTER_LINEAR : FILTER_POINT);
	m_pSkyDomeTextureRayleigh->SetClampingMode(0, 1, 1);
	m_pSkyDomeTextureRayleigh->UpdateTexStates();
#endif
}

void CREHDRSky::Init()
{
	if (!m_pStars)
		m_pStars = new CStars;

	//No longer defer texture creation, MT resource creation now supported
	//gRenDev->m_pRT->RC_GenerateSkyDomeTextures(this, SSkyLightRenderParams::skyDomeTextureWidth, SSkyLightRenderParams::skyDomeTextureHeight);
	GenerateSkyDomeTextures(SSkyLightRenderParams::skyDomeTextureWidth, SSkyLightRenderParams::skyDomeTextureHeight);
}

void CREHDRSky::mfPrepare(bool bCheckOverflow)
{
  if (bCheckOverflow)
    gRenDev->FX_CheckOverflow(0, 0, this);

	//gRenDev->FX_CheckOverflow( 0, 0, this );
	gRenDev->m_RP.m_pRE = this;
	gRenDev->m_RP.m_RendNumIndices = 0;
	gRenDev->m_RP.m_RendNumVerts = 0;
}


float CREHDRSky::mfDistanceToCameraSquared( Matrix34& matInst )
{
	return 999999.0f;
}


CREHDRSky::~CREHDRSky()
{
	SAFE_DELETE(m_pStars);

	SAFE_RELEASE(m_pSkyDomeTextureMie);
	SAFE_RELEASE(m_pSkyDomeTextureRayleigh);
}


//////////////////////////////////////////////////////////////////////////
// Stars
//////////////////////////////////////////////////////////////////////////


CStars::CStars()
: m_numStars(0)
, m_pStarMesh(0)
, m_pShader(0)
{
	if (LoadData())
	{
#ifndef NULL_RENDERER
    gRenDev->m_cEF.mfRefreshSystemShader("Stars", gRenDev->m_cEF.m_ShaderStars);
		m_pShader = gRenDev->m_cEF.m_ShaderStars;
#endif
	}
}


CStars::~CStars()
{
	SAFE_RELEASE(m_pStarMesh);
}



bool CStars::LoadData()
{
	const uint32 c_fileTag(0x52415453);				// "STAR"
	const uint32 c_fileVersion(0x00010001);
	const char c_fileName[] = "Libs/Sky/stars.dat";

	ICryPak* pPak(gEnv->pCryPak);
	if (pPak)
	{
		CInMemoryFileLoader file(pPak);
		if (file.FOpen(c_fileName, "rb"))
		{
			// read and validate header
			size_t itemsRead(0);
			uint32 fileTag(0);
			itemsRead = file.FRead(&fileTag, 1);
			if (itemsRead != 1 || fileTag != c_fileTag)
			{
				file.FClose();
				return false;
			}

			uint32 fileVersion(0);
			itemsRead = file.FRead(&fileVersion, 1);
			if (itemsRead != 1 || fileVersion != c_fileVersion)
			{
				file.FClose();
				return false;
			}

			// read in stars
			file.FRead(&m_numStars, 1);

			SVF_P3S_C4B_T2S* pData(new SVF_P3S_C4B_T2S[m_numStars]);

			for (unsigned int i(0); i<m_numStars; ++i)
			{
				float ra(0);
				file.FRead(&ra, 1);

				float dec(0);
				file.FRead(&dec, 1);

				uint8 r(0);
				file.FRead(&r, 1);

				uint8 g(0);
				file.FRead(&g, 1);

				uint8 b(0);
				file.FRead(&b, 1);

				uint8 mag(0);
				file.FRead(&mag, 1);

				Vec3 v;
				v.x = -cosf(DEG2RAD(dec)) * sinf(DEG2RAD(ra * 15.0f));
				v.y = cosf(DEG2RAD(dec)) * cosf(DEG2RAD(ra * 15.0f));
				v.z = sinf(DEG2RAD(dec));
				pData[i].xyz = v;

#if defined(DIRECT3D10)
				pData[i].color.dcolor = (mag << 24) + (b << 16) + (g << 8) + r;
#else
				pData[i].color.dcolor = (mag << 24) + (r << 16) + (g << 8) + b;
#endif
			}

			m_pStarMesh = gRenDev->CreateRenderMeshInitialized(pData, m_numStars, eVF_P3S_C4B_T2S, 0, 0, prtTriangleList, "Stars", "Stars");

			delete [] pData;

			// check if we read entire file
			long curPos(file.FTell());
			file.FSeek(0, SEEK_END);
			long endPos(file.FTell());
			if (curPos != endPos)
			{
				file.FClose();
				return false;
			}

			file.FClose();
			return true;
		}
	}
	return false;
}
